package com.tz.algorithm.xmlconvert;


import lombok.Data;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author lh
 * @description
 * @date 2022/10/20 23:56
 */
public class EntityGenerate {
    public static void main(String[] args) {
        ObjectSchema testSchema = new ObjectSchema();
        testSchema.setName("Test");
        testSchema.setType(FieldType.BOOLEAN);
        ObjectSchema arraySchema = new ObjectSchema();
        arraySchema.setName("failedRecord");
        arraySchema.setType(FieldType.ARRAY);
        arraySchema.setFieldSchemas(Arrays.asList(testSchema));
        ObjectSchema nameSchema = new ObjectSchema();
        nameSchema.setName("name");
        nameSchema.setType(FieldType.STRING);
        List<ObjectSchema> fieldSchemas=new ArrayList<>();
        fieldSchemas.add(arraySchema);
        fieldSchemas.add(nameSchema);
        ObjectSchema objectSchema = new ObjectSchema();
        objectSchema.setName("RootObj");
        objectSchema.setType(FieldType.OBJECT);
        objectSchema.setFieldSchemas(fieldSchemas);
        //初始化
        String rootPath="C:\\Users\\24964\\Desktop\\婷婷\\公招";
        String packageName="com.test";
        String classSuffix="Resp";
        GeneratorUtil.init(rootPath,packageName,classSuffix);
        GeneratorUtil.generate(objectSchema);
    }


}

class XMLUtil{
    public static ObjectSchema parseXml(String filePath,String entityName,String newName,Class clzz){
        // 创建SAXReader实例
        SAXReader reader = new SAXReader();
        // read()读取指定的XML文档并形成DOM树
        Document document=null;
        try {
            document = reader.read(new File(filePath));
        } catch (Exception e) {
            e.printStackTrace();
        }
        // getRootElement()获取根节点
        Element rootEle = document.getRootElement();
        // elements()获取根节点的子节点
        List<Element> bookEles = rootEle.elements();
        // 遍历子节点
        for (Element element : bookEles) {
            Attribute name = element.attribute("name");
            if(!entityName.equals(name.getValue())){
                continue;
            }
            ObjectSchema objectSchema = xmlNode2Schema(element, clzz);
            objectSchema.setType(FieldType.OBJECT);
            objectSchema.setName(newName);
            return objectSchema;
        }
    }

    public static ObjectSchema xmlNode2Schema(Element element,Class clzz) {
        ObjectSchema schema = new ObjectSchema();
        schema.setName(element.attributeValue("key"));
        schema.setFieldSchemas(new ArrayList<>());
        String type=element.attributeValue("");
        if("object".equals(type)){
            schema.setType(FieldType.OBJECT);
        }else if ("array".equals(type)){
            schema.setType(FieldType.ARRAY);
        }else{
            String methodName = element.attributeValue("method");
            Method[] methods = clzz.getMethods();
            for (Method method : methods) {
                if(!method.getName().equals(methodName)){
                    continue;
                }
                Type returnType = method.getGenericReturnType();
                String typeName = returnType.getTypeName();
                if(typeName.matches("^(int|Integer)$")){
                    schema.setType(FieldType.INTEGER);
                }else if(typeName.matches("^(boolean|Boolean)$")){
                    schema.setType(FieldType.BOOLEAN);
                }else if(typeName.matches("^(long|Long)$")){
                    schema.setType(FieldType.LONG);
                }else if(typeName.matches("^(String)$")){
                    schema.setType(FieldType.STRING);
                }
                break;
            }
        }
        List<Element> elements = element.elements();
        if(elements==null||elements.size()==0){
            return schema;
        }
        List<ObjectSchema> fieldSchemas=new ArrayList<>();
        for (Element childrenElement : elements) {
            String method = childrenElement.attributeValue("method");
            Class fieldClass = getFieldClass(clzz,method);
            fieldSchemas.add(xmlNode2Schema(childrenElement,fieldClass))
        }
        schema.setFieldSchemas(fieldSchemas);
        return schema;
    }

    private static Class getFieldClass(Class parent, String methodName){
        Method[] methods = parent.getMethods();
        for (Method method : methods) {
            if(!method.getName().equals(methodName)){
                continue;
            }
            Type returnType = method.getGenericReturnType();
            return returnType.getClass();
        }
        return null;
    }
}

class GeneratorUtil{
    private static String fileRootPath;
    private static String packageName;
    private static String classSuffix;

    public static void init(String rootPath, String packageNameStr,String suffix){
        fileRootPath=rootPath + "\\" + packageNameStr.replaceAll("\\\\.","\\");
        packageName=packageNameStr;
        classSuffix=suffix;
    }


    public static void generate(ObjectSchema schema){
        FieldType type = schema.getType();
        if(FieldType.OBJECT.equals(type)){
            generateObject(schema);
        }else if (FieldType.ARRAY.equals(type)){
            generateObject(schema);
        }
    }

    private static void generateObject(ObjectSchema schema){
        List<ObjectSchema> fieldSchemas = schema.getFieldSchemas();
        StringBuilder builder = new StringBuilder();
        //包名
        builder.append("package " + packageName).append(";\n");
        builder.append("\n");
        //导入import
        builder.append("import lombok.Data;\n");
        builder.append("import lombok.Builder;\n");
        if(Objects.nonNull(fieldSchemas)&&fieldSchemas.size()>0){
            boolean importedList = false;
            for (ObjectSchema fieldSchema : fieldSchemas) {
                if (!fieldSchema.getType().equals(FieldType.ARRAY)&&
                        !fieldSchema.getType().equals(FieldType.OBJECT)){
                    continue;
                }
                String className = fieldSchema.getClassName()+classSuffix;
                if(!importedList&&fieldSchema.getType().equals(FieldType.ARRAY)){
                    builder.append("import java.util.List;\n");
                    importedList=true;
                }
                builder.append("import "+packageName+"."+className+";\n");
            }
        }
        builder.append("\n");
        //注解
        builder.append("@Data\n");
        builder.append("@Builder\n");
        //具体内容
        builder.append("public class "+ schema.getClassName()+classSuffix).append(" {\n");
        //字段
        if(Objects.nonNull(fieldSchemas)&&fieldSchemas.size()>0){
            builder.append("\n");
            for (ObjectSchema fieldSchema : fieldSchemas) {
                builder.append("\t@JsonProperty(\""+fieldSchema.getName()+"\")\n");
                boolean addSuffix = false;
                if (fieldSchema.getType().equals(FieldType.ARRAY)||
                        fieldSchema.getType().equals(FieldType.OBJECT)){
                    addSuffix=true;
                }
                String className = fieldSchema.getClassName()+ (addSuffix ? classSuffix:"");
                String lowerCamelCaseName = fieldSchema.getLowerCamelCaseName();
                if(fieldSchema.getType().equals(FieldType.ARRAY)){
                    builder.append("\tprivate List<"+className+"> "+lowerCamelCaseName+";\n");
                }else{
                    builder.append("\tprivate "+className+" "+lowerCamelCaseName+";\n");
                }
                builder.append("\n");
                generate(fieldSchema);
            }
        }
        //结束符
        builder.append("}\n");
        System.out.println(builder.toString());
    }

}

@Data
class ObjectSchema {
    //带下划线的
    private String name;

    private String className;

    //首字母全大写的
    private String upperCamelCaseName;
    //首字母小写的
    private String lowerCamelCaseName;
    private FieldType type;
    private List<ObjectSchema> fieldSchemas;

    public void setName(String name) {
        this.name = name.toLowerCase();
        this.lowerCamelCaseName =underline2LowerCamelCase(this.name);
        String lowerTmp=this.lowerCamelCaseName.toLowerCase();
        this.upperCamelCaseName =(char)(lowerTmp.charAt(0)-32)+this.lowerCamelCaseName.substring(1);
        setClassName();
    }

    public void setType(FieldType type) {
        this.type = type;
        setClassName();
    }

    private void setClassName(){
        if(this.type==null||this.name==null){
            return;
        }
        if(FieldType.OBJECT.equals(type)){
            this.className=this.upperCamelCaseName;
        }else if (FieldType.ARRAY.equals(type)){
            this.className=this.upperCamelCaseName;
        }else if (FieldType.STRING.equals(type)){
            this.className="String";
        }else if (FieldType.BOOLEAN.equals(type)){
            this.className="Boolean";
        }else if (FieldType.INTEGER.equals(type)){
            this.className="Integer";
        }else if (FieldType.LONG.equals(type)){
            this.className="Long";
        }else{
            throw new IllegalArgumentException("不存在的类型："+this.type);
        }
    }

    private String underline2LowerCamelCase(String underline){
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < underline.length();) {
            if(underline.charAt(i)=='_'){
                builder.append((char)(underline.charAt(i+1)-32));
                i+=2;
            }else{
                builder.append(underline.charAt(i));
                i++;
            }
        }
        return builder.toString();
    }
}

enum FieldType{
    OBJECT,ARRAY,STRING,BOOLEAN,INTEGER,LONG
}
